package common

import (
	"gorm.io/gorm"
	"hobby-mate/cache"
	"hobby-mate/middleware/globalLogger"
	"reflect"
)

// BaseCURDImpl 实现 BaseCURD 接口
// ID问题：在entity中 谁是主键 则 增加tag `gorm:"primary_key"` 的字段为主键
type BaseCURDImpl struct {
	connection *gorm.DB
}

func CreateBaseCURDImpl(db *gorm.DB) *BaseCURDImpl {
	return &BaseCURDImpl{connection: db}
}

//-------------------------------------单条记录操作-------------------------------------

// Insert 添加一条记录
func (base *BaseCURDImpl) Insert(entity any) error {
	//给entity的BaseEntity赋值
	entityValue := reflect.ValueOf(entity)
	baseEntityField := entityValue.Elem().FieldByName("BaseEntity")
	if baseEntityField.IsValid() {
		baseEntityField.FieldByName("CreateBy").SetString(cache.UserInfos.AccountId)
		baseEntityField.FieldByName("CreateByName").SetString(cache.UserInfos.Username)
	}
	err := base.connection.Create(entity).Error
	if err != nil {
		globalLogger.Error(nil, err)
	}

	return err
}

// DeleteById 根据 主键 删除记录
func (base *BaseCURDImpl) DeleteById(entity any) error {
	err := base.connection.Delete(&entity).Error
	if err != nil {
		globalLogger.Error(nil, err)
	}
	return err
}

// UpdateById 根据 主键 更新记录
func (base *BaseCURDImpl) UpdateById(entity any) error {
	//TODO:需要判断是否存在主键、无主键则不执行
	return base.connection.Save(&entity).Error
}

// QueryById 根据 主键 查询记录
func (base *BaseCURDImpl) QueryById(key any, entity any) error {
	return base.connection.Find(entity, key).Error
}

// SaveOrUpdate 保存或更新记录 -- 有主键则更新，无主键则插入
func (base *BaseCURDImpl) SaveOrUpdate(entity any) error {
	return base.connection.Save(entity).Error
}

//-------------------------------------多条记录操作-------------------------------------
//-------------------------------------TODO: 这里的批量sql还需要参数，去给条件操作-------------------------------------

// InsertBatch 批量添加记录
func (base *BaseCURDImpl) InsertBatch(entity []any) error {
	return base.connection.CreateInBatches(&entity, len(entity)).Error
}

// DeleteBatch 批量删除记录  --入参为主键切片
func (base *BaseCURDImpl) DeleteBatch(entity []any) error {
	//gorm将会抛错ErrMissingWhereClause，所以需要加上Where条件
	return base.connection.Where("1 = 1").Delete(&entity).Error
}

// UpdateBatch 批量更新记录、把这一批记录更新为entityBody中的内容 根据这批主键更新
func (base *BaseCURDImpl) UpdateBatch(entityType any, entityBody []any) error {
	// 1. 获取主键字段的名称
	entityTypeValue := reflect.ValueOf(entityType)
	entityTypeElem := entityTypeValue.Elem()
	var primaryKeyField string
	for i := 0; i < entityTypeElem.NumField(); i++ {
		field := entityTypeElem.Type().Field(i)
		if field.Tag.Get("gorm") == "primary_key" {
			primaryKeyField = field.Name
			break
		}
	}
	// 2.将entityBody中的主键值设置到primaryKeys中
	var primaryKeys []any
	for _, entity := range entityBody {
		entityValue := reflect.ValueOf(entity)
		primaryKeyValue := entityValue.Elem().FieldByName(primaryKeyField).Interface()
		primaryKeys = append(primaryKeys, primaryKeyValue)
	}
	// 3. 使用收集的主键值执行更新操作
	return base.connection.Model(entityType).Where(primaryKeyField+" IN ?", primaryKeys).Updates(&entityBody).Error
}

// QueryByCondition 基础条件查询
// target 一边代表着查询的表，一边代表着查询结果赋值的对象
func (base *BaseCURDImpl) QueryByCondition(target any, conditionObj any) error {
	err := base.connection.Model(target).Where(conditionObj).Find(target).Error
	if err != nil {
		globalLogger.Error(nil, err)
	}
	return err
}

// QueryByPageCondition 分页条件查询
// target 查询结果赋值的对象
// conditionObj 查询条件
// conditionInMap in查询条件
// pageSize 每页大小
// currentPage 当前页
func (base *BaseCURDImpl) QueryByPageCondition(target any, conditionObj any, conditionIn map[string]any, query *PageBase) (*PageResult, error) {
	var totalRecords int64
	err := base.connection.
		Where(conditionObj).
		Where(conditionIn).
		Limit(query.PageSize).
		Offset((query.CurrentPage - 1) * query.PageSize).
		Find(target).
		Count(&totalRecords).
		Error
	if err != nil {
		globalLogger.Error(nil, err)
	}
	totalPages := (totalRecords + int64(query.PageSize) - 1) / int64(query.PageSize)
	result := &PageResult{
		TotalRecord: int(totalRecords),
		TotalPage:   int(totalPages),
		Data:        nil,
		PageBase:    *query,
	}
	return result, err
}
